package org.zt.java.dal.interceptor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.transaction.annotation.Transactional;
import org.zt.java.dal.config.DalConfig;
import org.zt.java.dal.config.vo.MethodInfo;
import org.zt.java.dal.config.vo.MethodRouterConfig;
import org.zt.java.dal.context.ContextHolder;
import org.zt.java.dal.datasource.DataSourceType;
import org.zt.java.dal.datasource.DynamicDataSource;
import org.zt.java.dal.util.DalConfigUtil;
import org.zt.java.dal.util.SpringContextHolder;


public class DynamicDataSourceParamsAdvice implements MethodInterceptor, Ordered {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	private DalConfig dalConfig;

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		try {
			// 记录数据源参数
			recordDataSourceParams(invocation);

			// 执行被拦截的方法
			return invocation.proceed();
		} finally {
			// 手动清理ContextHolder参数，避免在线程池重用线程导致的串号问题
			ContextHolder.popMethodInfo();
			if (ContextHolder.isStackEmpty()) {
				logger.debug(">>>清除dal环境变量");
				ContextHolder.clearAll();
			}
		}
	}

	@Override
	public int getOrder() {
		// 调整拦截器顺序，在事务拦截器执行之前设置好路由信息。
		// 小于Integer.MAX_VALUE即可，越小优先级越高
		return -1;
	}

	private DalConfig getDalConfig() {
		if (dalConfig == null) {
			DynamicDataSource dynamicDataSource = SpringContextHolder.getBean(DynamicDataSource.class);
			dalConfig = dynamicDataSource.getDalConfig();
		}

		return dalConfig;
	}

	private void recordDataSourceParams(MethodInvocation invocation) {
		String className = invocation.getThis().getClass().getName();
		String methodName = invocation.getMethod().getName();
		String methodParamType = DalConfigUtil.getMethodParam(invocation);

		DataSourceType use = DataSourceType.Default;
		MethodRouterConfig methodRouterConfig = DalConfigUtil.getMethodRouteConfig(this.getDalConfig(), invocation);
		if (methodRouterConfig != null) {
			use = methodRouterConfig.getUse();
		}

		Boolean tx = false;
		// 记录事务信息
		Transactional classTransactional = invocation.getThis().getClass().getAnnotation(Transactional.class);
		Transactional methodTransactional = invocation.getMethod().getAnnotation(Transactional.class);
		//类级别声明事务注解，且非只读，且方法没有声明事务
		if((classTransactional != null && !classTransactional.readOnly()) && methodTransactional == null){
			tx = true;
		}
		//方法级别声明注解，且非只读
		if (methodTransactional != null && !methodTransactional.readOnly()) {
			tx = true;
		}

		MethodInfo methodInfo = new MethodInfo(className, methodName, methodParamType, use, tx);
		ContextHolder.pushMethodInfo(methodInfo);

		logger.debug(
				"动态数据源参数: firstMethodDataSourceType={},firstClassName={},firstMethodName={}, firstMethodParam={},firstMethodTransactional={},globalTransactional={}, currentClassName={}, currentMethodName={},currentMethodParam={}",
				ContextHolder.getFirstMethodInfo().getUse(), ContextHolder.getFirstMethodInfo().getClassName(),
				ContextHolder.getFirstMethodInfo().getMethodName(),
				ContextHolder.getFirstMethodInfo().getMethodParamType(), ContextHolder.getFirstMethodInfo().getTx(),
				ContextHolder.isGlobalTransactional(), ContextHolder.getCurrentMethodInfo().getClassName(),
				ContextHolder.getCurrentMethodInfo().getMethodName(),
				ContextHolder.getCurrentMethodInfo().getMethodParamType());
	}


}
